package com.kcloud.commons.authorization;

import com.baomidou.mybatisplus.extension.parsers.ITableNameHandler;
import com.kcloud.commons.authorization.constants.AuthorizationConstants;
import com.kcloud.commons.authorization.exception.AuthorizationException;
import com.kcloud.commons.authorization.mp.handler.AuthorizationTableNameHandler;
import com.kcloud.commons.authorization.mp.parser.AttributeAuthorizationParser;
import com.kcloud.commons.authorization.mp.parser.AuthorizationTableNameParser;
import com.kcloud.commons.authorization.mp.plugins.AuthorizationPrepareStatementInterceptor;
import com.kcloud.commons.authorization.settings.biz.service.AuthUserService;
import com.kcloud.commons.entity.control.BizDomain;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 权限控制配置对象
 *
 * @author songhuiqing
 */
@Configuration
@ConfigurationProperties(prefix = "kcloud.authorization")
@Data
public class AuthorizationConfig {

    private List<BizDomain> initDomains; // 初始化业务域

    private static ThreadLocal<AuthorizationHeaders> bizDomainLocal = new ThreadLocal<>(); //当前业务域


    @Autowired(required = false)
    private AuthUserService authUserService;

    @Bean
    public Docket bizSettingsDocket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder().title("业务体系API").version("1.0.0")
                        .build()).select().paths(PathSelectors.ant("/bizSettings/**")).build();
    }


    /**
     * 权限表名处理器
     *
     * @return
     */
    @Bean
    public ITableNameHandler tableNameHandler() {
        return new AuthorizationTableNameHandler(this);
    }

    /**
     * 权限SQL拦截器
     *
     * @return
     */
    @Bean
    public AuthorizationPrepareStatementInterceptor authorizationInterceptor() {
        AuthorizationPrepareStatementInterceptor interceptor = new AuthorizationPrepareStatementInterceptor();
        //表名解析器
        AuthorizationTableNameParser tableNameParser = new AuthorizationTableNameParser();
        tableNameParser.setTableNameHandler(tableNameHandler());
        //表列解析器
//        AttributeAuthorizationParser columnParser = new AttributeAuthorizationParser();

        interceptor.setSqlParserList(Stream.of(tableNameParser).collect(Collectors.toList()));
        return interceptor;
    }

    /**
     * 权限拦截器注册
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean authorizationFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new AuthorizationFilter());
        registration.addUrlPatterns("/bizSettings/*");
        registration.setName("authorizationFilter");
        registration.setOrder(1);
        return registration;
    }

    /**
     * 获取表名
     *
     * @param originTableName 默认配置表
     * @return
     */
    public String getTableName(String originTableName) {
        String targetTableName = originTableName;
        switch (originTableName.toUpperCase()) {
            case AuthorizationConstants.DEFAULT_TABLE_BIZ_ENTITY:
                targetTableName = String.format(AuthorizationConstants.BIZ_ENTITY_TABLE_TPL, bizDomainLocal.get().getBizCode());
                break;
            case AuthorizationConstants.DEFAULT_TABLE_BIZ_FUNCTION:
                targetTableName = String.format(AuthorizationConstants.BIZ_FUNCTION_TABLE_TPL, bizDomainLocal.get().getBizCode());
                break;
            case AuthorizationConstants.DEFAULT_TABLE_USER_BIZ_FUNCTION:
                targetTableName = String.format(AuthorizationConstants.USER_FUNCTION_TABLE_TPL, bizDomainLocal.get().getBizCode());
                break;

        }
        return targetTableName;
    }

    /**
     * 获取授权用户信息，需要业务服务自己实现接口
     * @return
     */
    public AuthUser getAuthUser() {
        if(authUserService == null) {
            throw new AuthorizationException("no bean define AuthUserService!");
        }
        return authUserService.getAuthUser(bizDomainLocal.get().getUserId());
    }

    /**
     * 获取权限请求头
     * @return
     */
    public AuthorizationHeaders getAuthHeaders() {
        return bizDomainLocal.get();
    }

    public static class AuthorizationFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            String bizCode = request.getHeader(AuthorizationConstants.HEADER_KEY_BIZ_DOMAIN_CODE);
            String userId = request.getHeader(AuthorizationConstants.HEADER_KEY_USER_ID);
            String configId = request.getHeader(AuthorizationConstants.HEADER_KEY_BIZ_FUNCTION_CODE);
            if (bizCode == null || "".equals(bizCode)) {
                throw new AuthorizationException(String.format("header parameters %s must by existed!", AuthorizationConstants.HEADER_KEY_BIZ_DOMAIN_CODE));
            }
            //设置业务域编码到ThreadLocal中
            bizDomainLocal.set(new AuthorizationHeaders(bizCode, userId, configId));
            try {
                filterChain.doFilter(request, response);
            } finally {
                bizDomainLocal.remove();
            }

        }
    }
}
